package com.elitesland.system.service.impl;

import com.elitesland.core.base.ApiCode;
import com.elitesland.core.base.BaseModel;
import com.elitesland.core.base.PagingVO;
import com.elitesland.core.exception.BusinessException;
import com.elitesland.system.convert.SysRoleConvert;
import com.elitesland.system.entity.*;
import com.elitesland.system.param.SysRoleNewParam;
import com.elitesland.system.param.SysRoleQueryParam;
import com.elitesland.system.param.SysRoleUpdateParam;
import com.elitesland.system.repo.SysRoleRepo;
import com.elitesland.system.repo.SysRoleRepoProc;
import com.elitesland.system.service.SysPermissionService;
import com.elitesland.system.service.SysRolePermissionService;
import com.elitesland.system.service.SysRoleService;
import com.elitesland.system.service.SysUserRoleService;
import com.elitesland.system.vo.SysPermissionVO;
import com.elitesland.system.vo.SysRoleVO;
import com.google.common.collect.Lists;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <pre>
 * [功能说明]
 * </pre>
 *
 * @author Mir
 * @date 2020/7/5
 */
@Service
public class SysRoleServiceImpl implements SysRoleService {

    private SysRoleRepo sysRoleRepo;

    private SysPermissionService sysPermissionService;

    private SysUserRoleService sysUserRoleService;

    private SysRolePermissionService sysRolePermissionService;

    private JPAQueryFactory jpaQueryFactory;

    @Autowired
    public void setSysRoleRepo(SysRoleRepo sysRoleRepo) {
        this.sysRoleRepo = sysRoleRepo;
    }

    @Autowired
    public void setSysUserRoleService(SysUserRoleService sysUserRoleService) {
        this.sysUserRoleService = sysUserRoleService;
    }

    @Autowired
    public void setSysPermissionService(SysPermissionService sysPermissionService) {
        this.sysPermissionService = sysPermissionService;
    }

    @Autowired
    public void setSysRolePermissionService(SysRolePermissionService sysRolePermissionService) {
        this.sysRolePermissionService = sysRolePermissionService;
    }

    @Autowired
    public void setJpaQueryFactory(JPAQueryFactory jpaQueryFactory) {
        this.jpaQueryFactory = jpaQueryFactory;
    }

    private final QSysRoleDO roles = QSysRoleDO.sysRoleDO;

    private final QSysUserDO users = QSysUserDO.sysUserDO;

    private final QSysUserRoleDO userRoles = QSysUserRoleDO.sysUserRoleDO;

    @Override
    public PagingVO<SysRoleVO> search(SysRoleQueryParam param) {
        val roleItor = sysRoleRepo.findAll(SysRoleRepoProc.where(param), param.getPageRequest());

        val roles = roleItor.getContent();

        val roleIds = roles.stream().map(BaseModel::getId).collect(Collectors.toList());

        val us = sysUserRoleService.listUsersByRoleIds(roleIds);

        val ps = sysRolePermissionService.listPermissionsByRoleIds(roleIds);

        List<SysRoleVO> roleVos = roles.stream().map(r -> {
            val vo = new SysRoleVO();
            vo.setId(r.getId());
            vo.setCode(r.getCode());
            vo.setName(r.getName());
            vo.setEnabled(r.getEnabled());
            vo.setUsers(us.get(r.getId()));
            vo.setPermIds(ps.containsKey(r.getId()) ?
                    ps.get(r.getId()).stream().map(SysPermissionVO::getId).collect(Collectors.toList()) :
                    new ArrayList<>());

            return vo;
        }).collect(Collectors.toList());
        return PagingVO.<SysRoleVO>builder()
                .total(roleItor.getTotalElements())
                .records(roleVos)
                .build();
    }

    @Override
    public Optional<SysRoleDO> one(Long roleId) {
        return sysRoleRepo.findById(roleId);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Long create(SysRoleNewParam role) {
        val sysRole = QSysRoleDO.sysRoleDO;

        val existRolesItor = sysRoleRepo.findAll(sysRole.code.in(role.getCode()));
        val existRoles = Lists.newArrayList(existRolesItor);
        if (existRoles.size() > 0) {
            val codes = existRoles.stream().map(SysRoleDO::getCode).collect(Collectors.joining(", "));
            throw new BusinessException("角色代码重复: " + codes);
        }

        val tempRole = SysRoleConvert.INSTANCE.newParamToDO(role);

        val newRole = sysRoleRepo.save(tempRole);

        val permissions = sysPermissionService.listAllPermissionsByIds(role.getPermIds());
        val rolePermissionDOs = permissions.stream().map(p -> {
            return new SysRolePermissionDO()
                    .setRoleId(newRole.getId())
                    .setPermissionId(p.getId());
        }).collect(Collectors.toList());

        sysRolePermissionService.saveAll(rolePermissionDOs);

        return newRole.getId();
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void update(SysRoleUpdateParam reqRole) {
        val sysRole = QSysRoleDO.sysRoleDO;

        val roleOpt = sysRoleRepo.findById(reqRole.getId());
        if (roleOpt.isEmpty()) {
            throw new BusinessException("待更新的角色不存在");
        }

        val roleCount = sysRoleRepo.count(sysRole.code.eq(reqRole.getCode()).and(sysRole.id.ne(reqRole.getId())));
        if (roleCount > 0) {
            throw new BusinessException("角色编码：" + reqRole.getCode() + "， 已经存在");
        }

        val role = roleOpt.get();
        role.setCode(reqRole.getCode());
        role.setName(reqRole.getName());
        role.setEnabled(reqRole.getEnabled());

        val permissions = sysPermissionService.listAllPermissionsByIds(reqRole.getPermIds());
        val rolePermissionDOs = permissions.stream().map(p -> {
            return new SysRolePermissionDO()
                    .setRoleId(role.getId())
                    .setPermissionId(p.getId());
        }).collect(Collectors.toList());

        sysRolePermissionService.removePermissionsByRoleIds(Collections.singletonList(role.getId()));
        sysRolePermissionService.saveAll(rolePermissionDOs);

        sysRoleRepo.save(role);
    }

    @Override
    public Set<SysRoleVO> listByRoleIds(List<Long> roleIds) {
        return sysRoleRepo.findAllByIdIn(roleIds).stream().map(SysRoleConvert.INSTANCE::doToVo)
                .collect(Collectors.toSet());
    }

    @Override
    public List<SysRoleDO> listAll() {
        return sysRoleRepo.findAll();
    }

    @Override
    public List<String> listMenusById(Long id) {
        return sysRolePermissionService.listMenusByRoleId(id)
                .stream().map(m -> m.getId().toString())
                .collect(Collectors.toList());
    }

    @Override
    public List<String> listActionsById(Long id) {
        return sysRolePermissionService.listActionsByRoleId(id)
                .stream().map(a -> a.getId().toString())
                .collect(Collectors.toList());
    }

    @Override
    public Boolean switchRoleStatus(Long id) {
        val roleOpt = sysRoleRepo.findById(id);

        return roleOpt.map(r -> {
            r.setEnabled(!r.getEnabled());
            sysRoleRepo.save(r);
            return r.getEnabled();
        }).orElseThrow(
                new BusinessException(ApiCode.FAIL, "ID为：" + id + "，的角色不存在")
        );
    }
}
